package com.modebing.activiti7.service.impl;

import com.alibaba.nacos.common.utils.StringUtils;
import com.modebing.activiti7.service.ActivitiService;
import org.activiti.bpmn.model.*;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.Process;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ActivitiServiceImpl implements ActivitiService {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @Override
    public String deployProcess(MultipartFile file, String deploymentName) {
        // 校验文件是否为空
        if (file.isEmpty()) {
            return "请选择要上传的BPMN流程文件";
        }

        // 校验文件类型
        String fileName = file.getOriginalFilename();
        if (fileName != null && !fileName.endsWith(".bpmn") && !fileName.endsWith(".bpmn20.xml")) {
            return "请上传正确的BPMN文件（.bpmn或.bpmn20.xml格式）";
        }

        String name = fileName.endsWith(".bpmn") ? fileName.split(".bpmn")[0] : fileName.split(".bpmn20.xml")[0];

        try {
            // 创建部署构建器
            Deployment deployment = repositoryService.createDeployment()
                    // 设置部署名称（默认使用文件名）
                    .name(StringUtils.hasText(deploymentName) ? deploymentName : name)
                    // 添加上传的文件流
                    .addInputStream(fileName, file.getInputStream())
                    // 执行部署
                    .deploy();

            // 构建成功响应
            return String.format("流程部署成功！\n部署ID: %s\n部署名称: %s\n部署时间: %s\n包含流程定义数: %d",
                    deployment.getId(),
                    deployment.getName(),
                    deployment.getDeploymentTime(),
                    repositoryService.createProcessDefinitionQuery()
                            .deploymentId(deployment.getId())
                            .count());

        } catch (IOException e) {
            return "文件读取失败：" + e.getMessage();
        } catch (Exception e) {
            return "流程部署失败：" + e.getMessage();
        }
    }

    @Override
    public String startProcess(String businessKey, Map<String, String> variables) {
        String name = businessKey.split("-")[0]; // 业务key规则为：流程定义名 + "-" + 业务id

        try {
            // 1. 检查是否包含userId参数
            if (!variables.containsKey("userId")) {
                return "参数错误：缺少必要参数userId";
            }

            // 2. 根据流程名称查询流程定义
            List<ProcessDefinition> processDefinitions = repositoryService
                    .createProcessDefinitionQuery()
                    .processDefinitionName(name)
                    .latestVersion()
                    .list();

            // 3. 校验查询结果
            if (processDefinitions == null || processDefinitions.isEmpty()) {
                return "未找到名称为【" + name + "】的流程定义";
            }

            // 4. 获取流程定义的key
            ProcessDefinition processDefinition = processDefinitions.get(0);
            String processDefinitionKey = processDefinition.getKey();

            // 5. 转换变量类型
            Map<String, Object> processVariables = new HashMap<>(variables);

            // 6. 启动流程实例
            String processInstanceId = runtimeService
                    .startProcessInstanceByKey(processDefinitionKey, businessKey, processVariables)
                    .getId();

            return "流程启动成功！流程实例ID：" + processInstanceId +
                    "，使用的流程定义：" + processDefinition.getName() +
                    "（版本：" + processDefinition.getVersion() + "）";
        } catch (Exception e) {
            return "流程启动失败：" + e.getMessage();
        }
    }

    @Override
    public String completeTask(String businessKey, Map<String, Object> variables) {
        try {
            // 1. 根据 businessKey 找到运行中的流程实例
            ProcessInstance instance = runtimeService.createProcessInstanceQuery()
                    .processInstanceBusinessKey(businessKey)
                    .singleResult();
            if (instance == null) {
                return "未找到运行中的流程实例";
            }

            // 2. 找到该实例唯一待办任务
            Task task = taskService.createTaskQuery()
                    .processInstanceId(instance.getId())
                    .taskAssignee(variables.get("assignee").toString())
                    .singleResult();
            if (task == null) {
                return "当前流程实例没有待办任务";
            }

            // 3. 完成任务
            if (variables != null && !variables.isEmpty()) {
                taskService.complete(task.getId(), variables);
            } else {
                taskService.complete(task.getId());
            }

            return "success";
        } catch (Exception e) {
            return "complete error: " + e.getMessage();
        }
    }

    @Override
    public Map<String, Object> queryProcessSteps(String businessKey) {
        // 步骤状态map：key=步骤名称，value=状态（1=正常完成，0=拒绝/未通过）
        Map<String, Integer> stepStatusMap = new LinkedHashMap<>(); // 使用LinkedHashMap保证插入顺序
        Map<String, Object> result = new HashMap<>();
        String rejectionStep = null;
        boolean hasRejection = false;
        HistoricActivityInstance lastBusinessActivityBeforeRejection = null;
        boolean isProcessNormalEnded = false;

        try {
            // 1. 查询流程实例（运行中或历史）
            ProcessInstance processInstance = runtimeService
                    .createProcessInstanceQuery()
                    .processInstanceBusinessKey(businessKey)
                    .singleResult();

            HistoricProcessInstance historicInstance = null;
            String processInstanceId = null;
            String processDefinitionId = null;

            if (processInstance != null) {
                processInstanceId = processInstance.getId();
                processDefinitionId = processInstance.getProcessDefinitionId();
            } else {
                historicInstance = historyService
                        .createHistoricProcessInstanceQuery()
                        .processInstanceBusinessKey(businessKey)
                        .orderByProcessInstanceEndTime().desc()
                        .listPage(0, 1)
                        .stream()
                        .findFirst()
                        .orElse(null);

                if (historicInstance == null) {
                    result.put("steps", stepStatusMap);
                    result.put("rejectionStep", null);
                    result.put("hasRejection", false);
                    return result;
                }
                processInstanceId = historicInstance.getId();
                processDefinitionId = historicInstance.getProcessDefinitionId();
                isProcessNormalEnded = historicInstance.getEndTime() != null;
            }

            // 2. 获取流程定义中的关键节点（UserTask、StartEvent、EndEvent）
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
            org.activiti.bpmn.model.Process mainProcess = bpmnModel.getMainProcess();
            List<Map<String, String>> allSteps = new ArrayList<>();

            for (FlowElement element : mainProcess.getFlowElements()) {
                if (element instanceof UserTask
                        || element instanceof StartEvent
                        || element instanceof EndEvent) {
                    String activityId = element.getId();
                    String activityName = getActivityName(element); // 统一处理节点名称
                    allSteps.add(new HashMap<String, String>() {{
                        put("activityId", activityId);
                        put("activityName", activityName);
                        put("type", getElementType(element)); // 记录节点类型用于排序
                    }});
                }
            }

            // 3. 对节点进行排序：Start -> 业务步骤（UserTask）-> End
            Collections.sort(allSteps, (step1, step2) -> {
                String type1 = step1.get("type");
                String type2 = step2.get("type");

                // 排序优先级：Start(0) < UserTask(1) < End(2)
                Map<String, Integer> typeOrder = new HashMap<>();
                typeOrder.put("start", 0);
                typeOrder.put("userTask", 1);
                typeOrder.put("end", 2);

                return Integer.compare(typeOrder.get(type1), typeOrder.get(type2));
            });

            // 4. 查询历史活动，按执行时间排序
            List<HistoricActivityInstance> historicActivities = historyService
                    .createHistoricActivityInstanceQuery()
                    .processInstanceId(processInstanceId)
                    .orderByHistoricActivityInstanceStartTime().asc()
                    .list();

            // 5. 识别拒绝节点、最后业务步骤和正常结束状态
            for (int i = 0; i < historicActivities.size(); i++) {
                HistoricActivityInstance activity = historicActivities.get(i);
                String activityName = activity.getActivityName();
                String activityType = activity.getActivityType();

                if (activityName != null && activityName.contains("拒绝")) {
                    rejectionStep = activityName;
                    hasRejection = true;
                    // 查找拒绝前的最后一个UserTask
                    if (i > 0) {
                        for (int j = i - 1; j >= 0; j--) {
                            HistoricActivityInstance prevActivity = historicActivities.get(j);
                            if ("userTask".equals(prevActivity.getActivityType())) {
                                lastBusinessActivityBeforeRejection = prevActivity;
                                break;
                            }
                        }
                    }
                    break;
                }

                if (!hasRejection && "endEvent".equals(activityType)) {
                    isProcessNormalEnded = true;
                }
            }

            // 6. 构建步骤状态（按排序后的顺序添加到结果）
            for (Map<String, String> step : allSteps) {
                String activityId = step.get("activityId");
                String activityName = step.get("activityName");

                // 处理Start节点
                if ("Start".equals(activityName)) {
                    stepStatusMap.put(activityName, 1);
                    continue;
                }

                // 处理End节点
                if ("End".equals(activityName)) {
                    int endStatus = hasRejection ? 0 : (isProcessNormalEnded ? 1 : 0);
                    stepStatusMap.put(activityName, endStatus);
                    continue;
                }

                // 处理业务步骤（UserTask）
                if (hasRejection) {
                    if (lastBusinessActivityBeforeRejection != null
                            && activityId.equals(lastBusinessActivityBeforeRejection.getActivityId())) {
                        stepStatusMap.put(activityName, 0);
                    }
                } else {
                    boolean isFinished = historicActivities.stream()
                            .anyMatch(a -> a.getActivityId().equals(activityId) && a.getEndTime() != null);
                    stepStatusMap.put(activityName, isFinished ? 1 : 0);
                }
            }

            // 7. 组装结果
            result.put("steps", stepStatusMap);
            result.put("rejectionStep", rejectionStep);
            result.put("hasRejection", hasRejection);

        } catch (Exception e) {
            e.printStackTrace();
            result.put("steps", stepStatusMap);
            result.put("rejectionStep", null);
            result.put("hasRejection", false);
            result.put("error", "查询失败：" + e.getMessage());
        }

        return result;
    }

    @Override
    public void getInstanceDiagramByBusinessKey(String businessKey, HttpServletResponse response) {
        try {
            // 1. 查询流程实例（先查运行中，再查历史）
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                    .processInstanceBusinessKey(businessKey)
                    .singleResult();

            HistoricProcessInstance historicProcessInstance = null;
            if (processInstance == null) {
                historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                        .processInstanceBusinessKey(businessKey)
                        .orderByProcessInstanceStartTime().desc()
                        .listPage(0, 1)
                        .stream()
                        .findFirst()
                        .orElse(null);
            }

            // 2. 验证流程实例是否存在
            if (processInstance == null && historicProcessInstance == null) {
                throw new RuntimeException("未找到流程实例：" + businessKey);
            }

            // 3. 获取流程实例ID和流程定义ID
            String processInstanceId = processInstance != null ?
                    processInstance.getId() : historicProcessInstance.getId();
            String processDefinitionId = processInstance != null ?
                    processInstance.getProcessDefinitionId() : historicProcessInstance.getProcessDefinitionId();

            // 4. 确定需要高亮的节点
            List<String> highLightedActivities = new ArrayList<>();

            // 判断流程是否已结束
            boolean isProcessEnded = historicProcessInstance != null &&
                    historicProcessInstance.getEndTime() != null;

            if (isProcessEnded) {
                // 流程已结束：高亮结束节点
                List<HistoricActivityInstance> endActivities = historyService
                        .createHistoricActivityInstanceQuery()
                        .processInstanceId(processInstanceId)
                        .activityType("endEvent")
                        .finished()
                        .list();

                highLightedActivities.addAll(endActivities.stream()
                        .map(HistoricActivityInstance::getActivityId)
                        .collect(Collectors.toList()));
            } else if (processInstance != null) {
                // 流程运行中：高亮当前活动节点
                if (processInstance.isSuspended()) {
                    highLightedActivities.addAll(runtimeService.getActiveActivityIds(processInstanceId));
                } else {
                    highLightedActivities.addAll(runtimeService.getActiveActivityIds(processInstanceId));

                    // 如果没有活动节点，查找最近的历史节点
                    if (highLightedActivities.isEmpty()) {
                        HistoricActivityInstance latestActivity = historyService
                                .createHistoricActivityInstanceQuery()
                                .processInstanceId(processInstanceId)
                                .orderByHistoricActivityInstanceEndTime().desc()
                                .listPage(0, 1)
                                .stream()
                                .findFirst()
                                .orElse(null);

                        if (latestActivity != null) {
                            highLightedActivities.add(latestActivity.getActivityId());
                        } else {
                            // 如果找不到最近活动，尝试通过历史活动查询开始节点
                            List<HistoricActivityInstance> startActivities = historyService
                                    .createHistoricActivityInstanceQuery()
                                    .processInstanceId(processInstanceId)
                                    .activityType("startEvent")
                                    .list();

                            if (!startActivities.isEmpty()) {
                                highLightedActivities.add(startActivities.get(0).getActivityId());
                            }
                        }
                    }
                }
            }

            // 5. 如果仍然没有高亮节点，尝试通过类类型判断查找开始节点
            if (highLightedActivities.isEmpty()) {
                // 先尝试从历史活动中找
                List<HistoricActivityInstance> startActivities = historyService
                        .createHistoricActivityInstanceQuery()
                        .processInstanceId(processInstanceId)
                        .activityType("startEvent")
                        .list();

                if (!startActivities.isEmpty()) {
                    highLightedActivities.add(startActivities.get(0).getActivityId());
                } else {
                    // 通过BPMN模型查找开始节点（不依赖getType()方法）
                    BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
                    org.activiti.bpmn.model.Process mainProcess = bpmnModel.getMainProcess();

                    // 获取所有流程元素（使用反射机制兼容不同版本）
                    List<FlowElement> flowElements = getFlowElements(mainProcess);

                    // 筛选出开始节点（通过类型判断）
                    for (FlowElement element : flowElements) {
                        if (element instanceof StartEvent) {
                            highLightedActivities.add(element.getId());
                            break;
                        }
                    }
                }
            }

            // 6. 生成并返回流程图
            BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
            ProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator();

            // 设置响应头
            response.setContentType("image/svg+xml");
            response.setHeader("Cache-Control", "no-store, no-cache");

            try (InputStream is = diagramGenerator.generateDiagram(
                    bpmnModel,
                    highLightedActivities,
                    Collections.emptyList(),
                    "宋体", "宋体", "宋体")) {
                org.springframework.util.FileCopyUtils.copy(is, response.getOutputStream());
            }
        } catch (Exception e) {
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 辅助方法：获取节点名称
     */
    private String getActivityName(FlowElement element) {
        if (element instanceof EndEvent) {
            return StringUtils.hasText(element.getName()) ? element.getName() : "End";
        } else if (element instanceof StartEvent) {
            return StringUtils.hasText(element.getName()) ? element.getName() : "Start";
        } else {
            return StringUtils.hasText(element.getName()) ? element.getName() : element.getId();
        }
    }

    /**
     * 辅助方法：获取节点类型（用于排序）
     */
    private String getElementType(FlowElement element) {
        if (element instanceof StartEvent) {
            return "start";
        } else if (element instanceof EndEvent) {
            return "end";
        } else {
            return "userTask";
        }
    }

    /**
     * 通过反射获取流程元素，兼容不同Activiti版本
     */
    private List<FlowElement> getFlowElements(org.activiti.bpmn.model.Process process) {
        try {
            // 尝试获取flowElements字段
            Field flowElementsField = Process.class.getDeclaredField("flowElements");
            flowElementsField.setAccessible(true);
            return (List<FlowElement>) flowElementsField.get(process);
        } catch (NoSuchFieldException e) {
            // 如果没有flowElements字段，尝试其他方式
            try {
                // 尝试调用getFlowElements()方法
                Method getFlowElementsMethod = Process.class.getMethod("getFlowElements");
                return (List<FlowElement>) getFlowElementsMethod.invoke(process);
            } catch (Exception ex) {
                // 所有方法都失败时返回空列表
                return Collections.emptyList();
            }
        } catch (Exception e) {
            return Collections.emptyList();
        }
    }
}
